#!/usr/bin/env python3
import curses
from curses import panel
import os
import sys
import json
import locale
import time
from pathlib import Path

# 配置应用目录
HOME = str(Path.home())
APP_DIR = os.path.join(HOME, ".reader")
PROGRESS_FILE = os.path.join(APP_DIR, "progress.json")
CONFIG_FILE = os.path.join(APP_DIR, "config.json")

# 确保应用目录存在
os.makedirs(APP_DIR, exist_ok=True)

# 支持的编码列表
SUPPORTED_ENCODINGS = [
    "utf-8", "gb2312", "gb18030", "gbk", 
    "big5", "utf-16", "latin-1", "iso-8859-1"
]

# 定义按键的ASCII码值
KEY_ESCAPE = 27          # ESC键
KEY_ENTER_1 = 10         # 回车键
KEY_ENTER_2 = 13         # 回车键的另一个ASCII码
KEY_PAGE_UP = 339        # 页上键
KEY_PAGE_DOWN = 343      # 页下键
KEY_HOME = 360           # Home键
KEY_END = 358            # End键

class Window:
    """基础窗口类"""
    def __init__(self, height, width, y, x):
        # 获取终端尺寸
        max_y, max_x = curses.LINES - 1, curses.COLS - 1
        
        # 确保窗口尺寸和位置有效
        self.height = max(1, min(height, max_y + 1))
        self.width = max(1, min(width, max_x + 1))
        self.y = max(0, min(y, max_y - self.height + 1))
        self.x = max(0, min(x, max_x - self.width + 1))
        
        self.window = curses.newwin(self.height, self.width, self.y, self.x)
        self.panel = panel.new_panel(self.window)
        self.hidden = False

    def hide(self):
        self.panel.hide()
        self.hidden = True
        panel.update_panels()
        curses.doupdate()

    def show(self):
        self.panel.show()
        self.hidden = False
        panel.update_panels()
        curses.doupdate()

    def is_hidden(self):
        return self.hidden

    def get_window(self):
        return self.window

    def resize(self, height, width, y, x):
        try:
            # 获取当前终端尺寸
            max_y, max_x = curses.LINES - 1, curses.COLS - 1
            
            # 确保窗口尺寸有效（不超过终端大小）
            self.height = max(1, min(height, max_y + 1))
            self.width = max(1, min(width, max_x + 1))
            
            # 确保窗口位置有效（不会超出终端边界）
            self.y = max(0, min(y, max_y - self.height + 1))
            self.x = max(0, min(x, max_x - self.width + 1))
            
            # 先尝试调整窗口大小
            self.window.resize(self.height, self.width)
            
            # 安全地移动窗口
            if self.y >= 0 and self.x >= 0 and \
               self.y + self.height <= max_y + 1 and \
               self.x + self.width <= max_x + 1:
                self.window.mvwin(self.y, self.x)
            else:
                # 如果位置无效，重新创建窗口
                self.window = curses.newwin(self.height, self.width, self.y, self.x)
            
            # 更新面板
            self.panel = panel.new_panel(self.window)
            if self.hidden:
                self.panel.hide()
            panel.update_panels()
            curses.doupdate()
            return True
        except curses.error as e:
            # 处理窗口操作错误
            return False

    def safe_addstr(self, y, x, text, attr=0):
        """安全地添加字符串，避免超出窗口边界"""
        if y < 0 or y >= self.height:
            return False
        if x < 0 or x >= self.width:
            return False
        # 截断文本以适应窗口宽度
        max_length = self.width - x
        if max_length <= 0:
            return False
        text = text[:max_length]
        try:
            self.window.addstr(y, x, text, attr)
            return True
        except curses.error:
            return False

    def refresh(self):
        """刷新窗口"""
        self.window.refresh()
        curses.doupdate()

class FileBrowser(Window):
    """文件浏览器窗口"""
    def __init__(self, height, width, y, x):
        super().__init__(height, width, y, x)
        self.current_dir = self._get_last_dir()
        self.files = []
        self.selected = 0
        self.scroll = 0
        self.load_files()
        self.status_bar = Window(1, width, y + height - 1, x)
        self.status_bar.get_window().bkgd(' ', curses.color_pair(3))
        self.update_status()

    def _get_last_dir(self):
        """获取上次浏览的目录"""
        try:
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r') as f:
                    config = json.load(f)
                    if "last_dir" in config and os.path.isdir(config["last_dir"]):
                        return config["last_dir"]
        except:
            pass
        return HOME

    def _save_last_dir(self):
        """保存当前目录"""
        try:
            config = {}
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r') as f:
                    config = json.load(f)
            config["last_dir"] = self.current_dir
            with open(CONFIG_FILE, 'w') as f:
                json.dump(config, f)
        except:
            pass

    def load_files(self):
        """加载当前目录下的文件"""
        try:
            entries = os.listdir(self.current_dir)
            # 先显示目录，再显示文件，都按字母顺序排序
            dirs = []
            files = []
            for entry in entries:
                full_path = os.path.join(self.current_dir, entry)
                if os.path.isdir(full_path) and not entry.startswith('.'):
                    dirs.append(entry + '/')
                elif os.path.isfile(full_path) and entry.lower().endswith('.txt'):
                    # 获取阅读进度百分比
                    progress_percent = self._get_file_progress(full_path)
                    if progress_percent > 0:
                        files.append(f"{entry} ({progress_percent}%)")
                    else:
                        files.append(entry)
            
            # 排序
            dirs.sort(key=str.lower)
            files.sort(key=str.lower)
            
            # 添加返回上一级
            self.files = ['../'] + dirs + files
            self.selected = 0
            self.scroll = 0
        except Exception as e:
            self.files = [f"Error: {str(e)}"]
            self.selected = 0
            self.scroll = 0

    def _get_file_progress(self, file_path):
        """获取文件的阅读进度百分比"""
        try:
            if os.path.exists(PROGRESS_FILE):
                with open(PROGRESS_FILE, 'r') as f:
                    progress_data = json.load(f)
                    if isinstance(progress_data, dict):
                        if file_path in progress_data:
                            if isinstance(progress_data[file_path], dict) and "scroll" in progress_data[file_path]:
                                scroll_pos = progress_data[file_path]["scroll"]
                            else:
                                scroll_pos = progress_data[file_path]
                        else:
                            return 0
                    else:
                        return 0
                    
                    # 尝试获取文件总行数来计算百分比
                    try:
                        with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                            content = f.read()
                            lines = content.replace('\r\n', '\n').replace('\r', '\n').split('\n')
                            total_lines = max(1, len(lines))
                            return min(100, max(0, int((scroll_pos / total_lines) * 100)))
                    except:
                        return 0
            return 0
        except:
            return 0

    def update_status(self):
        """更新状态栏"""
        win = self.status_bar.get_window()
        win.erase()
        self.status_bar.safe_addstr(0, 0, f" 目录: {self.current_dir} ")
        self.status_bar.safe_addstr(0, self.width - 20, f" 选中: {self.selected + 1}/{len(self.files)} ")
        self.status_bar.refresh()

    def navigate(self, direction):
        """导航文件列表"""
        if direction == "up":
            self.selected = max(0, self.selected - 1)
        elif direction == "down":
            self.selected = min(len(self.files) - 1, self.selected + 1)
        elif direction == "page_up":
            self.selected = max(0, self.selected - (self.height - 2))
        elif direction == "page_down":
            self.selected = min(len(self.files) - 1, self.selected + (self.height - 2))

        # 调整滚动位置
        visible_lines = self.height - 2
        if self.selected < self.scroll:
            self.scroll = self.selected
        elif self.selected >= self.scroll + visible_lines:
            self.scroll = self.selected - visible_lines + 1

        self.update()
        self.update_status()

    def enter(self):
        """进入选中的目录或打开选中的文件"""
        if not self.files:
            return None

        selected_file = self.files[self.selected]
        # 移除可能包含的进度百分比
        if ' (' in selected_file and selected_file.endswith(')'):
            selected_file = selected_file[:selected_file.rfind(' (')]
            
        full_path = os.path.abspath(os.path.join(self.current_dir, selected_file))

        if selected_file.endswith('/') or selected_file == '../':
            # 进入目录
            self.current_dir = full_path
            self._save_last_dir()
            self.load_files()
            self.update()
            self.update_status()
            return None
        else:
            # 打开文件
            return full_path

    def update(self):
        """更新窗口显示"""
        win = self.get_window()
        win.erase()
        win.box()
        self.safe_addstr(0, 2, " 文件浏览器 ")
        # 显示操作提示
        self.safe_addstr(0, self.width - 25, " h:帮助 | r:最近阅读 ")

        visible_lines = self.height - 2
        display_files = self.files[self.scroll:self.scroll + visible_lines]

        for i, file in enumerate(display_files):
            y = i + 1
            x = 2
            if self.scroll + i == self.selected:
                # 高亮选中项
                self.safe_addstr(y, x, file[:self.width - 4], curses.color_pair(4))
            else:
                self.safe_addstr(y, x, file[:self.width - 4])

        self.refresh()

    def resize(self, height, width, y, x):
        super().resize(height, width, y, x)
        self.status_bar.resize(1, width, y + height - 1, x)
        self.update_status()
        self.update()

class Reader(Window):
    """阅读器窗口"""
    def __init__(self, height, width, y, x):
        super().__init__(height, width, y, x)
        self.file_path = None
        self.content = []
        self.scroll = 0
        self.encoding = self._get_default_encoding()
        self.status_bar = Window(1, width, y + height - 1, x)
        self.status_bar.get_window().bkgd(' ', curses.color_pair(3))
        self.update_status()

    def _get_default_encoding(self):
        """获取默认编码"""
        try:
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r') as f:
                    config = json.load(f)
                    if "default_encoding" in config and config["default_encoding"] in SUPPORTED_ENCODINGS:
                        return config["default_encoding"]
        except:
            pass
        return "utf-8"

    def _save_default_encoding(self):
        """保存默认编码"""
        try:
            config = {}
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r') as f:
                    config = json.load(f)
            config["default_encoding"] = self.encoding
            with open(CONFIG_FILE, 'w') as f:
                json.dump(config, f)
        except:
            pass

    def load_file(self, file_path, scroll_pos=None):
        """加载文件内容（支持指定滚动位置）"""
        self.file_path = file_path
        self.content = []
        # 优先使用指定的滚动位置，否则从进度文件读取
        if scroll_pos is not None:
            self.scroll = scroll_pos
        else:
            self.scroll = self._get_progress(file_path)
        
        try:
            # 尝试用指定编码打开文件
            with open(file_path, 'r', encoding=self.encoding, errors='replace') as f:
                content = f.read()
            
            # 处理不同换行符
            content = content.replace('\r\n', '\n').replace('\r', '\n')
            
            # 按行分割
            lines = content.split('\n')
            
            # 处理长行，自动折行
            max_line_length = self.width - 4
            if max_line_length > 0:
                for line in lines:
                    # 拆分长行
                    for i in range(0, len(line), max_line_length):
                        self.content.append(line[i:i + max_line_length])
                    # 添加空行分隔原始行
                    self.content.append('')
            else:
                self.content = lines
            
            # 确保滚动位置不超出内容长度
            self.scroll = min(self.scroll, max(0, len(self.content) - (self.height - 2)))
            self.update()
            self.update_status()
            # 加载成功后更新最近阅读记录
            self._update_recent_record()
            return True
        except Exception as e:
            self.content = [
                f"无法打开文件: {str(e)}", 
                f"当前编码: {self.encoding}",
                "按 e 键更改编码"
            ]
            self.update()
            self.update_status()
            return False

    def _update_recent_record(self):
        """更新最近阅读记录（含时间戳）"""
        if not self.file_path:
            return
        try:
            progress_data = {}
            if os.path.exists(PROGRESS_FILE):
                with open(PROGRESS_FILE, 'r') as f:
                    progress_data = json.load(f)
            
            # 存储格式：{文件路径: {"scroll": 滚动位置, "last_read": 时间戳}}
            progress_data[self.file_path] = {
                "scroll": self.scroll,
                "last_read": time.time()
            }
            
            with open(PROGRESS_FILE, 'w') as f:
                json.dump(progress_data, f, indent=2)
        except:
            pass

    def _calculate_progress_percent(self):
        """计算阅读进度百分比"""
        if not self.content or len(self.content) <= 1:
            return 0
        return min(100, max(0, int((self.scroll / len(self.content)) * 100)))

    def change_encoding(self, encoding):
        """更改编码并重新加载文件"""
        if encoding in SUPPORTED_ENCODINGS and encoding != self.encoding:
            self.encoding = encoding
            self._save_default_encoding()
            if self.file_path:
                self.load_file(self.file_path)

    def _get_progress(self, file_path):
        """获取文件的阅读进度（兼容新旧格式）"""
        try:
            if os.path.exists(PROGRESS_FILE):
                with open(PROGRESS_FILE, 'r') as f:
                    progress_data = json.load(f)
                    if isinstance(progress_data, dict) and file_path in progress_data:
                        # 新格式：含scroll和last_read
                        if isinstance(progress_data[file_path], dict) and "scroll" in progress_data[file_path]:
                            return progress_data[file_path]["scroll"]
                        # 旧格式：仅存scroll
                        else:
                            return progress_data[file_path]
        except:
            pass
        return 0

    def _save_progress(self):
        """保存当前阅读进度（同时更新最近阅读时间）"""
        if not self.file_path:
            return
            
        try:
            progress_data = {}
            if os.path.exists(PROGRESS_FILE):
                with open(PROGRESS_FILE, 'r') as f:
                    progress_data = json.load(f)
            
            # 保存格式：包含滚动位置和最新阅读时间
            progress_data[self.file_path] = {
                "scroll": self.scroll,
                "last_read": time.time()
            }
            
            with open(PROGRESS_FILE, 'w') as f:
                json.dump(progress_data, f, indent=2)
        except:
            pass

    def navigate(self, direction):
        """导航内容"""
        visible_lines = self.height - 2
        
        if direction == "up":
            self.scroll = max(0, self.scroll - 1)
        elif direction == "down":
            self.scroll = min(len(self.content) - 1, self.scroll + 1)
        elif direction == "page_up":
            self.scroll = max(0, self.scroll - visible_lines)
        elif direction == "page_down":
            self.scroll = min(len(self.content) - 1, self.scroll + visible_lines)
        elif direction == "top":
            self.scroll = 0
        elif direction == "bottom":
            self.scroll = max(0, len(self.content) - visible_lines)

        self.update()
        self.update_status()
        self._save_progress()

    def update_status(self):
        """更新状态栏"""
        if not self.file_path:
            return
            
        win = self.status_bar.get_window()
        win.erase()
        
        # 文件名和阅读进度百分比
        file_name = os.path.basename(self.file_path)
        progress_percent = self._calculate_progress_percent()
        self.status_bar.safe_addstr(0, 2, f" 文件: {file_name} 已阅读: {progress_percent}% ")
        
        # 编码
        self.status_bar.safe_addstr(0, self.width // 3, f" 编码: {self.encoding} (e:更改) ")
        
        # 进度（页数）提示移至右下角
        total_lines = max(1, len(self.content))
        visible_lines = self.height - 2
        current_page = max(1, (self.scroll // visible_lines) + 1)
        total_pages = max(1, (total_lines + visible_lines - 1) // visible_lines)
        # 移动到右下角
        self.status_bar.safe_addstr(0, self.width - 20, f" 页: {current_page}/{total_pages} ")
        
        self.status_bar.refresh()

    def update(self):
        """更新窗口显示"""
        win = self.get_window()
        win.erase()
        win.box()
        self.safe_addstr(0, 2, " 小说阅读 ")
        # 移除了窗口顶部的帮助提示

        visible_lines = self.height - 2
        display_content = self.content[self.scroll:self.scroll + visible_lines]

        for i, line in enumerate(display_content):
            y = i + 1
            x = 2
            # 确保不会超出窗口宽度
            line = line[:self.width - 4]
            self.safe_addstr(y, x, line)

        self.refresh()

    def resize(self, height, width, y, x):
        # 在阅读模式下，阅读器窗口占满整个屏幕宽度
        super().resize(height, width, y, 0)
        self.status_bar.resize(1, width, y + height - 1, 0)
        # 重新处理长行并刷新
        if self.file_path:
            self.load_file(self.file_path)
        else:
            self.update()
            self.update_status()

class EncodingSelector(Window):
    """编码选择窗口"""
    def __init__(self, height, width, y, x):
        super().__init__(height, width, y, x)
        self.selected = SUPPORTED_ENCODINGS.index(self._get_default_encoding())
        self.scroll = 0
        self.update()

    def _get_default_encoding(self):
        """获取默认编码"""
        try:
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r') as f:
                    config = json.load(f)
                    if "default_encoding" in config and config["default_encoding"] in SUPPORTED_ENCODINGS:
                        return config["default_encoding"]
        except:
            pass
        return "utf-8"

    def navigate(self, direction):
        """导航选项，支持滚动"""
        visible_items = self.height - 4
        
        if direction == "up":
            self.selected = max(0, self.selected - 1)
        elif direction == "down":
            self.selected = min(len(SUPPORTED_ENCODINGS) - 1, self.selected + 1)
        elif direction == "page_up":
            self.selected = max(0, self.selected - visible_items)
        elif direction == "page_down":
            self.selected = min(len(SUPPORTED_ENCODINGS) - 1, self.selected + visible_items)
            
        # 调整滚动位置
        if self.selected < self.scroll:
            self.scroll = self.selected
        elif self.selected >= self.scroll + visible_items:
            self.scroll = self.selected - visible_items + 1
            
        self.update()

    def get_selected(self):
        """获取选中的编码"""
        return SUPPORTED_ENCODINGS[self.selected]

    def update(self):
        """更新窗口显示"""
        win = self.get_window()
        win.erase()
        win.box()
        self.safe_addstr(0, 2, " 选择文件编码 ")

        visible_items = self.height - 4
        start = self.scroll
        end = self.scroll + visible_items
        
        for i in range(start, min(end, len(SUPPORTED_ENCODINGS))):
            y = (i - start) + 2
            x = 2
            if i == self.selected:
                self.safe_addstr(y, x, f"> {SUPPORTED_ENCODINGS[i]}", curses.color_pair(4))
            else:
                self.safe_addstr(y, x, f"  {SUPPORTED_ENCODINGS[i]}")

        # 显示导航提示
        self.safe_addstr(self.height - 2, 2, " ↑↓:选择 | PgUp/PgDn:翻页 | Enter:确认 | Esc:返回 ")
        self.refresh()

class ThemeSelector(Window):
    """主题选择窗口"""
    def __init__(self, height, width, y, x):
        super().__init__(height, width, y, x)
        self.themes = ["浅色 (白背景黑字)", "深色 (黑背景白字)"]
        self.selected = self._get_default_theme()
        self.update()

    def _get_default_theme(self):
        """获取默认主题"""
        try:
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r') as f:
                    config = json.load(f)
                    if "theme" in config and config["theme"] in [0, 1]:
                        return config["theme"]
        except:
            pass
        return 0  # 默认浅色

    def _save_default_theme(self):
        """保存默认主题"""
        try:
            config = {}
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, 'r') as f:
                    config = json.load(f)
            config["theme"] = self.selected
            with open(CONFIG_FILE, 'w') as f:
                json.dump(config, f)
        except:
            pass

    def navigate(self, direction):
        """导航选项"""
        if direction == "up":
            self.selected = (self.selected - 1) % len(self.themes)
        elif direction == "down":
            self.selected = (self.selected + 1) % len(self.themes)
        self.update()

    def get_selected(self):
        """获取选中的主题"""
        return self.selected

    def apply_selected(self):
        """应用选中的主题并保存"""
        self._save_default_theme()
        apply_theme(self.selected)

    def update(self):
        """更新窗口显示"""
        win = self.get_window()
        win.erase()
        win.box()
        self.safe_addstr(0, 2, " 选择主题 ")

        for i, theme in enumerate(self.themes):
            y = i + 2
            x = 2
            if i == self.selected:
                self.safe_addstr(y, x, f"> {theme}", curses.color_pair(4))
            else:
                self.safe_addstr(y, x, f"  {theme}")

        self.safe_addstr(self.height - 2, 2, " 按 Enter 确认，按 Esc 返回 ")
        self.refresh()

class RecentFilesWindow(Window):
    """最近阅读文件列表窗口"""
    def __init__(self, height, width, y, x):
        super().__init__(height, width, y, x)
        self.recent_files = self._load_recent_files()  # 格式：[(文件路径, 文件名, 最近阅读时间, 滚动位置), ...]
        self.selected = 0
        self.scroll = 0
        self.update()

    def _format_time(self, timestamp):
        """格式化时间戳为可读格式（YYYY-MM-DD HH:MM）"""
        try:
            return time.strftime("%Y-%m-%d %H:%M", time.localtime(timestamp))
        except:
            return "未知时间"

    def _load_recent_files(self):
        """加载最近阅读的文件（最多9个）"""
        recent_files = []
        try:
            if os.path.exists(PROGRESS_FILE):
                with open(PROGRESS_FILE, 'r') as f:
                    progress_data = json.load(f)
                
                # 筛选出包含last_read时间戳的文件（新格式）
                valid_files = []
                for file_path, data in progress_data.items():
                    # 跳过旧格式（仅存scroll的）和无效文件
                    if isinstance(data, dict) and "last_read" in data and "scroll" in data:
                        if os.path.exists(file_path) and os.path.isfile(file_path):
                            valid_files.append({
                                "path": file_path,
                                "name": os.path.basename(file_path),
                                "time": data["last_read"],
                                "scroll": data["scroll"]
                            })
                
                # 按阅读时间降序排序（最新的在前），取前9个
                valid_files.sort(key=lambda x: x["time"], reverse=True)
                recent_files = valid_files[:9]
                
                # 转换为显示所需格式
                return [
                    (item["path"], item["name"], self._format_time(item["time"]), item["scroll"])
                    for item in recent_files
                ]
        except:
            pass
        return recent_files

    def navigate(self, direction):
        """导航最近阅读列表"""
        if not self.recent_files:
            return
            
        visible_items = self.height - 4
        
        if direction == "up":
            self.selected = max(0, self.selected - 1)
        elif direction == "down":
            self.selected = min(len(self.recent_files) - 1, self.selected + 1)
        elif direction == "page_up":
            self.selected = max(0, self.selected - visible_items)
        elif direction == "page_down":
            self.selected = min(len(self.recent_files) - 1, self.selected + visible_items)
            
        # 调整滚动位置
        if self.selected < self.scroll:
            self.scroll = self.selected
        elif self.selected >= self.scroll + visible_items:
            self.scroll = self.selected - visible_items + 1
            
        self.update()

    def get_selected_file(self):
        """获取选中的文件信息（路径和滚动位置）"""
        if 0 <= self.selected < len(self.recent_files):
            return {
                "path": self.recent_files[self.selected][0],
                "scroll": self.recent_files[self.selected][3]
            }
        return None

    def update(self):
        """更新最近阅读列表显示"""
        win = self.get_window()
        win.erase()
        win.box()
        self.safe_addstr(0, 2, " 最近阅读的文件 (最多9个) ", curses.A_BOLD)

        # 显示提示（无最近阅读文件）
        if not self.recent_files:
            self.safe_addstr(2, 2, " 暂无最近阅读的文件 ", curses.color_pair(2))
            self.safe_addstr(self.height - 2, 2, " 按 Esc 返回 ")
            self.refresh()
            return

        # 显示列表（支持滚动）
        visible_items = self.height - 4
        start = self.scroll
        end = self.scroll + visible_items
        
        for i in range(start, min(end, len(self.recent_files))):
            y = (i - start) + 2
            x = 2
            file_path, file_name, read_time, _ = self.recent_files[i]
            
            # 截断过长的文件名（保留前30个字符）
            display_name = file_name[:30] + "..." if len(file_name) > 30 else file_name
            # 截断过长的路径（显示最后40个字符）
            display_path = "..." + file_path[-40:] if len(file_path) > 43 else file_path
            
            # 高亮选中项
            if i == self.selected:
                # 第一行：文件名 + 最近阅读时间
                self.safe_addstr(y, x, f"> {display_name}", curses.color_pair(4))
                self.safe_addstr(y, self.width - 25, f" 阅读时间: {read_time}", curses.color_pair(4))
                # 第二行：文件路径（缩进显示）
                self.safe_addstr(y + 1, x + 2, f"路径: {display_path}", curses.color_pair(4))
            else:
                self.safe_addstr(y, x, f"  {display_name}")
                self.safe_addstr(y, self.width - 25, f" 阅读时间: {read_time}")
                self.safe_addstr(y + 1, x + 2, f"路径: {display_path}")
            # 每行文件占2行（文件名+路径）
            i += 1

        # 显示操作提示
        self.safe_addstr(self.height - 2, 2, " ↑↓:选择 | Enter:打开 | PgUp/PgDn:翻页 | Esc:返回 ")
        self.refresh()

    def refresh_list(self):
        """刷新最近阅读列表（重新加载数据）"""
        self.recent_files = self._load_recent_files()
        self.selected = 0
        self.scroll = 0
        self.update()

def apply_theme(theme_id):
    """应用主题设置"""
    # 初始化颜色对
    # 1: 边框
    # 2: 文本
    # 3: 状态栏
    # 4: 选中项
    
    if theme_id == 0:  # 浅色主题: 白色背景，黑色文字
        curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
        curses.init_pair(2, curses.COLOR_BLACK, curses.COLOR_WHITE)
        curses.init_pair(3, curses.COLOR_BLACK, curses.COLOR_WHITE)
        curses.init_pair(4, curses.COLOR_BLUE, curses.COLOR_WHITE)
    else:  # 暗色主题: 黑色背景，白色文字
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
        curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_BLACK)
        curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_BLUE)
        curses.init_pair(4, curses.COLOR_CYAN, curses.COLOR_BLACK)

    # 设置默认颜色
    curses.curs_set(0)  # 隐藏光标
    curses.use_default_colors()
    curses.doupdate()

def main(stdscr):
    # 初始化curses
    locale.setlocale(locale.LC_ALL, '')
    curses.cbreak()
    curses.noecho()
    stdscr.keypad(True)
    curses.start_color()
    curses.use_default_colors()
    curses.curs_set(0)  # 隐藏光标

    # 获取默认主题
    default_theme = 0
    try:
        if os.path.exists(CONFIG_FILE):
            with open(CONFIG_FILE, 'r') as f:
                config = json.load(f)
                if "theme" in config and config["theme"] in [0, 1]:
                    default_theme = config["theme"]
    except:
        pass

    # 应用主题
    apply_theme(default_theme)

    # 获取屏幕尺寸
    height, width = stdscr.getmaxyx()
    
    # 确保窗口有足够的宽度
    min_width = 80
    min_height = 24
    if width < min_width or height < min_height:
        stdscr.clear()
        stdscr.addstr(0, 0, f"请调整终端窗口大小至少为 {min_width}x{min_height}")
        stdscr.addstr(1, 0, "按任意键退出...")
        stdscr.refresh()
        stdscr.getch()
        return

    # 创建核心窗口
    file_browser = FileBrowser(height - 2, width // 2, 1, 0)
    reader = Reader(height - 2, width // 2, 1, width // 2)
    reader.hide()
    
    # 创建功能窗口（初始隐藏）
    menu = Window(1, width, 0, 0)  # 顶部菜单
    help_window = Window(height - 4, width - 4, 2, 2)  # 帮助窗口
    encoding_selector = EncodingSelector(15, 40, height//2 -7, width//2 -20)  # 编码选择
    theme_selector = ThemeSelector(8, 40, height//2 -4, width//2 -20)  # 主题选择
    
    # 动态计算最近阅读窗口的尺寸，确保适合终端大小
    recent_win_width = min(100, width - 10)  # 最大100，最小为终端宽度-10
    recent_win_x = max(0, (width - recent_win_width) // 2)  # 水平居中
    recent_files_window = RecentFilesWindow(18, recent_win_width, height//2 -9, recent_win_x)  # 最近阅读列表
    
    # 隐藏所有功能窗口
    help_window.hide()
    encoding_selector.hide()
    theme_selector.hide()
    recent_files_window.hide()

    # 初始化顶部菜单
    menu_win = menu.get_window()
    menu_win.bkgd(' ', curses.color_pair(3))
    menu.safe_addstr(0, 2, " 小说阅读器 ", curses.A_BOLD)
    menu.safe_addstr(0, max(2, width - 40), " h:帮助 | e:编码 | t:主题 | r:最近阅读 ")
    menu.refresh()

    # 初始状态：显示文件浏览器
    current_view = "browser"
    file_browser.update()

    # 帮助信息
    help_text = [
        "文件浏览器操作:",
        "  ↑/↓: 上下移动 | PgUp/PgDn: 翻页 | Enter: 进入目录/打开文件",
        "  快捷键: h(帮助) | e(编码) | t(主题) | r(最近阅读) | q(退出)",
        "",
        "阅读模式操作:",
        "  ↑/↓: 上下滚动 | PgUp/PgDn: 翻页 | Home: 顶部 | End: 末尾",
        "  快捷键: b(返回列表) | h(帮助) | e(编码) | t(主题) | r(最近阅读) | q(退出)",
        "",
        "最近阅读操作:",
        "  ↑↓: 选择文件 | Enter: 打开文件 | Esc: 返回当前视图",
        "  PgUp/PgDn: 翻页浏览更多最近文件",
        "",
        "全局说明:",
        "  - 最近阅读列表最多显示9个最新阅读的文件",
        "  - 阅读进度自动保存，重新打开可恢复上次位置",
        "  - 支持多种编码格式，可手动切换适配不同文件"
    ]

    # 主循环
    while True:
        # 处理窗口大小变化
        new_height, new_width = stdscr.getmaxyx()
        if new_height != height or new_width != width:
            # 检查最小尺寸
            if new_width < min_width or new_height < min_height:
                stdscr.clear()
                stdscr.addstr(0, 0, f"窗口太小，请调整至至少 {min_width}x{min_height}")
                stdscr.addstr(1, 0, "按任意键继续...")
                stdscr.refresh()
                stdscr.getch()
                continue
                
            # 更新窗口尺寸
            height, width = new_height, new_width
            stdscr.clear()
            
            # 调整顶部菜单
            menu.resize(1, width, 0, 0)
            menu_win = menu.get_window()
            menu_win.erase()  # 清除原有内容
            menu_win.bkgd(' ', curses.color_pair(3))
            menu.safe_addstr(0, 2, " 小说阅读器 ", curses.A_BOLD)
            # 重新计算右侧文本位置，确保不会重叠
            right_text_x = max(2, width - 40)
            menu.safe_addstr(0, right_text_x, " h:帮助 | e:编码 | t:主题 | r:最近阅读 ")
            menu.refresh()
            
            # 调整核心窗口（根据当前视图）
            if current_view == "browser":
                file_browser.resize(height - 2, width // 2, 1, 0)
                reader.resize(height - 2, width // 2, 1, width // 2)
                reader.hide()
            else:  # 阅读模式
                reader.resize(height - 2, width, 1, 0)
                file_browser.resize(height - 2, width // 2, 1, 0)
                file_browser.hide()
            
            # 调整功能窗口位置（居中显示）
            help_window.resize(height - 4, width - 4, 2, 2)
            encoding_selector.resize(15, 40, height//2 -7, width//2 -20)
            theme_selector.resize(8, 40, height//2 -4, width//2 -20)
            
            # 重新计算最近阅读窗口尺寸和位置
            recent_win_width = min(100, width - 10)
            recent_win_x = max(0, (width - recent_win_width) // 2)
            recent_files_window.resize(18, recent_win_width, height//2 -9, recent_win_x)

        # 显示帮助窗口（优先显示）
        if not help_window.is_hidden():
            win = help_window.get_window()
            win.erase()
            win.box()
            help_window.safe_addstr(0, 2, " 帮助信息 ", curses.A_BOLD)
            for i, line in enumerate(help_text):
                if i + 1 >= height - 5:
                    break
                help_window.safe_addstr(i + 1, 2, line)
            help_window.safe_addstr(height - 5, 2, " 按任意键关闭帮助 ")
            help_window.refresh()

        # 等待用户输入
        key = stdscr.getch()

        # 关闭帮助窗口（优先处理）
        if not help_window.is_hidden():
            help_window.hide()
            # 刷新当前视图
            if current_view == "browser":
                file_browser.refresh()
            else:
                reader.refresh()
            continue

        # 处理最近阅读窗口（优先级高于其他功能窗口）
        if not recent_files_window.is_hidden():
            if key == KEY_ESCAPE:
                # 关闭最近阅读窗口，返回原视图
                recent_files_window.hide()
                if current_view == "browser":
                    file_browser.refresh()
                else:
                    reader.refresh()
            elif key == KEY_ENTER_1 or key == KEY_ENTER_2:
                # 打开选中的最近阅读文件
                selected_file = recent_files_window.get_selected_file()
                if selected_file and "path" in selected_file:
                    file_path = selected_file["path"]
                    scroll_pos = selected_file.get("scroll", 0)
                    if os.path.exists(file_path):
                        # 切换到阅读模式
                        current_view = "reader"
                        file_browser.hide()
                        reader.resize(height - 2, width, 1, 0)
                        reader.load_file(file_path, scroll_pos)
                        reader.show()
                    # 关闭最近阅读窗口
                    recent_files_window.hide()
            elif key == curses.KEY_UP:
                recent_files_window.navigate("up")
            elif key == curses.KEY_DOWN:
                recent_files_window.navigate("down")
            elif key == KEY_PAGE_UP:
                recent_files_window.navigate("page_up")
            elif key == KEY_PAGE_DOWN:
                recent_files_window.navigate("page_down")
            continue

        # 处理编码选择窗口
        if not encoding_selector.is_hidden():
            if key == KEY_ESCAPE:
                encoding_selector.hide()
                if current_view == "browser":
                    file_browser.refresh()
                else:
                    reader.refresh()
            elif key == KEY_ENTER_1 or key == KEY_ENTER_2:
                # 应用选中的编码
                selected_encoding = encoding_selector.get_selected()
                reader.change_encoding(selected_encoding)
                encoding_selector.hide()
                reader.refresh()
            elif key == curses.KEY_UP:
                encoding_selector.navigate("up")
            elif key == curses.KEY_DOWN:
                encoding_selector.navigate("down")
            elif key == KEY_PAGE_UP:
                encoding_selector.navigate("page_up")
            elif key == KEY_PAGE_DOWN:
                encoding_selector.navigate("page_down")
            continue

        # 处理主题选择窗口
        if not theme_selector.is_hidden():
            if key == KEY_ESCAPE:
                theme_selector.hide()
                if current_view == "browser":
                    file_browser.refresh()
                else:
                    reader.refresh()
            elif key == KEY_ENTER_1 or key == KEY_ENTER_2:
                # 应用选中的主题
                theme_selector.apply_selected()
                # 刷新所有窗口
                menu.refresh()
                if current_view == "browser":
                    file_browser.refresh()
                else:
                    reader.refresh()
                theme_selector.hide()
            elif key == curses.KEY_UP:
                theme_selector.navigate("up")
            elif key == curses.KEY_DOWN:
                theme_selector.navigate("down")
            continue

        # 处理全局快捷键
        if key == ord('h'):
            # 显示/隐藏帮助窗口
            help_window.show() if help_window.is_hidden() else help_window.hide()
            continue
        elif key == ord('t'):
            # 显示主题选择窗口
            theme_selector.show()
            continue
        elif key == ord('e'):
            # 显示编码选择窗口（仅在阅读模式有效）
            if current_view == "reader":
                encoding_selector.show()
            continue
        elif key == ord('r'):
            # 显示最近阅读列表（刷新最新数据）
            recent_files_window.refresh_list()
            recent_files_window.show()
            continue
        elif key == ord('q'):
            # 退出程序（保存阅读进度）
            if current_view == "reader" and reader.file_path:
                reader._save_progress()
            break

        # 处理视图切换（阅读模式 → 浏览模式）
        if key == ord('b') and current_view == "reader":
            current_view = "browser"
            # 保存当前阅读进度
            reader._save_progress()
            # 调整窗口大小并切换视图
            reader.resize(height - 2, width // 2, 1, width // 2)
            reader.hide()
            file_browser.resize(height - 2, width // 2, 1, 0)
            file_browser.show()
            file_browser.update()
            continue

        # 处理文件浏览器视图
        if current_view == "browser":
            if key == curses.KEY_UP:
                file_browser.navigate("up")
            elif key == curses.KEY_DOWN:
                file_browser.navigate("down")
            elif key == KEY_PAGE_UP:
                file_browser.navigate("page_up")
            elif key == KEY_PAGE_DOWN:
                file_browser.navigate("page_down")
            elif key == KEY_ENTER_1 or key == KEY_ENTER_2:
                # 打开选中的文件
                file_path = file_browser.enter()
                if file_path and os.path.isfile(file_path):
                    current_view = "reader"
                    file_browser.hide()
                    reader.resize(height - 2, width, 1, 0)
                    reader.load_file(file_path)
                    reader.show()
            # 刷新浏览器
            file_browser.refresh()

        # 处理阅读视图
        elif current_view == "reader":
            if key == curses.KEY_UP:
                reader.navigate("up")
            elif key == curses.KEY_DOWN:
                reader.navigate("down")
            elif key == KEY_PAGE_UP:
                reader.navigate("page_up")
            elif key == KEY_PAGE_DOWN:
                reader.navigate("page_down")
            elif key == KEY_HOME:
                reader.navigate("top")
            elif key == KEY_END:
                reader.navigate("bottom")
            # 刷新阅读器
            reader.refresh()

    # 退出清理
    curses.nocbreak()
    stdscr.keypad(False)
    curses.echo()
    curses.endwin()

if __name__ == "__main__":
    curses.wrapper(main)
